#include <iostream>
#include <string>

#if 0
    // 继承
    using CStrRef = const std::string &; // 简化代码
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){}
        // Person(const std::string &name)
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID){};
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }
    private: // 父类的私有成员可以被继承，但不可访问
        std::string name;
        int age;
        std::string ID;
    };

    // 定义这个类的时候会发现，成员变量和上面类会有重复
    // 为了提高代码的复用性，引入了继承
    // 继承：一个类继承另外一个类的成员变量和成员函数
    // 这个public代表的是继承权限
    class Student:public Person
    {
    public:
    private:
        // 继承了父类，这三个变量就不用定了
        // std::string name;
        // int age;
        // std::string ID;
        int score;
    };

    int main()
    {
        Student s;
        s.show(); // 这个函数是继承自父类的
        return 0;
    }
#endif

#if 0
    // public公有继承
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID){};
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }
    private: // 父类的私有成员可以被继承，但不可访问
        std::string name;
        int age;
        std::string ID;
    };

    class Student:public Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID):Person(name, age, ID){}
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123");
        s.show(); 
        return 0;
    }
#endif

#if 0
    // private私有继承
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID){};
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }
    private:
        std::string name;
        int age;
        std::string ID;
    };

    class Student:private Person
    {
    public:
        // 父类的成员变量私有，可以继承，但不能用
        // 子类可以调用父类的构造函数对父类的变量进行初始化，这个函数得在初始化列表中调用
        // 调用 Person 的构造函数，并传入 name, age, ID 作为参数。（这里的 name, age, ID 是从 Student 构造函数的参数传递过来的，然后再 把它们传递给 Person 的构造函数）
        // 这发生在 Student 构造函数体 {} 执行之前，目的是让 Person 先构造，初始化 Person 里的成员变量
        // 在 C++ 中，子类的构造函数执行之前，必须先构造父类。这是因为子类继承了父类的所有成员（包括 private 成员），而这些成员只能由父类的构造函数初始化，子类自己是无法直接访问 private 成员的。
        // 所以，父类必须先构造，否则子类无法继承和使用父类的成员。
        /*
            如果 Student 构造函数的参数和 Person 需要的不一样（比如 Student 只接收 studentID）
            那 Student 就得自己补充 name 和 age，这时候 Person 的参数就不是直接从 Student 构造函数来的了。
            Student(const string& studentID) 
            : Person("Default Name", 18, studentID){}  // name 和 age 不是从 Student 传来的
        */
        Student(CStrRef name, int age, CStrRef ID):Person(name, age, ID){}
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123");
        s.show(); // 私有继承，父类中所有成员在子类中都不可见 
        return 0;
    }
#endif

#if 0
    // protected保护继承
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID){};
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }
    private:
        std::string name;
        int age;
        std::string ID;
    };

    class Student:protected Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID):Person(name, age, ID)
        {
            // 派生类成员访问（可以最直接访问）
            show(); // 保护继承，本类和本类的派生类都可以访问
        }
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123");
        // 派生类对象访问（不可直接访问）
        s.show(); // 保护继承，本类和本类的派生类都可以用
        return 0;
    }
#endif

#if 0
    // 最常用的还是public公有继承
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID){};
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }
    // 降级成protected，这样它的子类也可以使用这些对象
    // 但是不允许随意修改一个类的访问权限
    // 开闭原则：对修改关闭，对扩展开放（扩展不是指在原类上进行扩展，而是在继承它之后，在新的类上进行扩展，尽量不要改动原类）
    protected: 
        std::string name;
        int age;
        std::string ID;
    };

    class Student:public Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID):Person(name, age, ID)
        {
            this->age = -1;
        }
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123");
        s.show(); 
        return 0;
    }
#endif

#if 0
    // 父子类构建和析构的顺序（父类先构造，子类先析构）
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){std::cout<<"父类构造函数!\n";}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID)
        {
            std::cout<<"父类构造函数!\n";
        }
        ~Person()
        {
            std::cout<<"父类析构函数!\n";
        }
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }

    protected: 
        std::string name;
        int age;
        std::string ID;
    };

    class Student:public Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID, int score):Person(name, age, ID)
        {
            std::cout<<"子类构造函数!\n";
            this->score = score;
        }
        ~Student()
        {
            std::cout<<"子类析构函数!\n";
        }
        // 子类成员变量多一个分数，把分数也show一下
        void show()
        {
            std::cout<<"分数："<<score<<std::endl;
        }
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123", 98);
        // 子类与父类定义同名函数时，子类对象调用的是子类函数
        s.show(); // 调的是自己的show,不是父类的show
        return 0;
    }
#endif

#if 0
    // 那如果父子类同名的函数构成了重载呢？
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){std::cout<<"父类构造函数!\n";}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID)
        {
            std::cout<<"父类构造函数!\n";
        }
        ~Person()
        {
            std::cout<<"父类析构函数!\n";
        }
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }

    protected: 
        std::string name;
        int age;
        std::string ID;
    };

    class Student:public Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID, int score):Person(name, age, ID)
        {
            std::cout<<"子类构造函数!\n";
            this->score = score;
        }
        ~Student()
        {
            std::cout<<"子类析构函数!\n";
        }
        // 加个参数，与父类的show构成重载
        void show(int a)
        {
            std::cout<<"分数："<<score<<std::endl;
        }
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123", 98);
        // 子类与父类定义同名函数时，子类对象调用的只能是子类函数，就算构成重载也不行（名词遮蔽）
        // s.show(); // 事实证明调用的还是子类的show
        s.show(1); 
        s.Person::show(); // 硬要调父类中的show（一个子类对象强行调父类函数很奇怪，与其这样写不如定义一个Person的对象去show它）
        return 0;
    }
#endif

#if 1
    // 在子类的show里先调父类的show，再加上自己要show的分数
    using CStrRef = const std::string &;
    class Person
    {
    public:
        Person():name(""), age(0), ID(""){std::cout<<"父类构造函数!\n";}
        Person(CStrRef name, int age, CStrRef ID):name(name), age(age), ID(ID)
        {
            std::cout<<"父类构造函数!\n";
        }
        ~Person()
        {
            std::cout<<"父类析构函数!\n";
        }
        void show()
        {
            std::cout<<"名字："<<name<<" 年龄："<<age<<" 身份证："<<ID<<std::endl;
        }

    protected: 
        std::string name;
        int age;
        std::string ID;
    };

    class Student:public Person
    {
    public:
        Student(CStrRef name, int age, CStrRef ID, int score):Person(name, age, ID)
        {
            std::cout<<"子类构造函数!\n";
            this->score = score;
        }
        ~Student()
        {
            std::cout<<"子类析构函数!\n";
        }
        void show()
        {   
            // 功能的叠加
            // 在父类的功能基础上叠加子类的新功能
            Person::show();
            std::cout<<"分数："<<score<<std::endl;
        }
    private:
        int score;
    };

    int main()
    {
        Student s("张三", 20, "123", 98);
        s.show(); 
        return 0;
    }
#endif